package my.Imitation.writing;
/**
 * Created with IntelliJ IDEA.
 *
 * @Author: Tom
 * @Date: 2022/01/21/21:20
 * @Description:
 */


import java.util.Arrays;

/**
 *@ClassName ArrayList
 *@Description
 *@Author 王琛
 *@Date 2022/1/21 21:20
 @Version 1.0
 */
public class MyArrayList<E> {
    int size = 0;
    Object[] elements;

    private static final int DEFAULT_SIZE = 10;
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 10;
    private static final Object[] DEFAULT_EMPTY_ARRAY = {};
    public MyArrayList() {
        this.elements = DEFAULT_EMPTY_ARRAY;
    }
    public MyArrayList(int capacity) {
        if (capacity > 0){
            this.elements = new Object[capacity];
        }else if (capacity == 0){
            this.elements = DEFAULT_EMPTY_ARRAY;
        }else{
            throw new IllegalArgumentException("错误的参数 :" + capacity);
        }
    }

    public boolean add(E e){
        checkCapacity(size + 1);
        elements[size++] = e;
        return true;
    }

    public E remove(){
        if(elements == DEFAULT_EMPTY_ARRAY){
            throw new NullPointerException();
        }
        return castElement(--size);
    }

    public E remove(int index){
        rangeCheck(index);
        E element = castElement(index);
        int newBound = size - index - 1;
        if (newBound > 0) {
            System.arraycopy(elements,index + 1,elements,index,newBound);
            elements[--size] = null;
        }
        return element;
    }

    public boolean remove(Object o) {
        if(o == null){
            for (int i = 0; i < elements.length; i++) {
                if (elements[i] == null) {
                    fastRemove(i);
                    return true;
                }
            }
        }  else {
              for (int i = 0; i < elements.length; i++) {
                  if (o.equals(elements[i])) {
                      fastRemove(i);
                      return true;
                  }
              }
        }
        return false;
    }

    private void fastRemove(int index) {
        int newBound = size - index - 1;
        if (newBound > 0) {
            System.arraycopy(elements,index + 1,elements,index,newBound);
            elements[--size] = null;
        }
    }

    private void rangeCheck(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException();
        }
    }

    public boolean isEmpty(){
        return size == 0;
    }

    public int size() {
        return size;
    }

    public int indexOf(Object o) {
        if (o == null){
            for (int i = 0; i < elements.length; i++) {
                if (elements[i] == null) {
                    return i;
                }
            }
        }else {
            for (int i = 0; i < elements.length; i++) {
                if (o.equals(elements[i])) {
                    return i;
                }
            }
        }
        return -1;
    }
    public boolean contains(Object o){
        return indexOf(o) >= 0;
    }

    private void checkCapacity(int capacity) {
        finallyChange(checkFirstAdd(elements,capacity));
    }
    private int checkFirstAdd(Object[] elements,int capacity) {
        if (elements == DEFAULT_EMPTY_ARRAY){
            return Math.max(DEFAULT_SIZE,capacity);
        }
        return capacity;
    }
    private void finallyChange(int capacity){
        if (capacity - elements.length > 0){
            grow(capacity);
        }
    }

    private void grow(int capacity) {
        int oldCapacity = elements.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if(newCapacity - capacity < 0){
            newCapacity = capacity;
        }else if (newCapacity - MAX_ARRAY_SIZE > 0){
            newCapacity =  hugeCapacity(capacity);
        }
       elements = Arrays.copyOf(elements,newCapacity);
    }

    private int hugeCapacity(int capacity) {
        if (capacity < 0) {
            throw new ArrayIndexOutOfBoundsException();
        }
        return capacity > MAX_ARRAY_SIZE ? Integer.MAX_VALUE : capacity;
    }

    @SuppressWarnings("unchecked")
    E castElement(int index){
        return (E)elements[index];
    }


    public static void main(String[] args) {
        MyArrayList<String> list = new MyArrayList<>();
        list.add("1");
        System.out.println(list.remove());
    }
}
